package wortubung.core;

import static wortubung.util.CommonUtils.*;

import java.util.HashMap;

import wortubung.util.LatinScript;
import wortubung.util.CyrillicScript;
import wortubung.util.GreekScript;
import wortubung.util.TransliterateException;

public enum LANG {

    // European -
    de (3, true,  true,  true ),
    en (0, false, false, true ),
    es (2, false, true,  true ),
    fr (2, false, true,  true ),
    it (2, false, true,  true ),
    la (2, false, true,  true ),
    el (0, false, true,  false),
    ru (2, false, true,  false),

    // West-South Asia -
    hi (2, false, true,  false),
    ar (2, false, true,  false),
    fa (2, false, true,  false),
    he (2, false, true,  false),
    tr (0, false, true,  true ),
    sa (2, false, true,  false),

    // East Asia -
    zh,
    ja,
    ko;

    // key is <lang>-<lang>; <lang> is the 2-letter code;
    // First is the language to use, second is language to display. 
    private static HashMap<String,String> languageNames;
    
    static {
    	languageNames = new HashMap<String,String>();
    	try {
    		String[] lines = readFileFromCPAsString("languages-in-languages.txt").split("\n");
    		String[] sa = lines[0].substring(lines[0].indexOf(':') + 1).split("\\|");
    		trim(sa);
    		LANG[] langs = new LANG[sa.length];
    		int i;
    		for (i=0; i<langs.length; ++i)
    			langs[i] = valueOf(sa[i]);
    		for (i=1; i<lines.length; ++i) {
    			String line = lines[i];
    			int idx = line.indexOf(':');
    			if (idx <= 0)
    				continue;
    			String langToDisplay = line.substring(0, idx).trim();
    			sa = line.substring(idx+1).split("\\|");
    			trim(sa);
    			for (int j=0; j<langs.length; ++j)
    				languageNames.put(langs[j].name() + '-' + langToDisplay, langs[j].toVernacular(at(sa, j)));
    		}
    	} catch(Exception e) {
    		e.printStackTrace();
    	}
    }
    private static String WORD_PLACEHOLDER = "~";

    private boolean hasNounGender;
    private boolean hasGenderNeuter;
    private boolean isIrregularPlural;
    private boolean isConjugated;
    private boolean isLatinScript;

    private LANG() { this(0, false, false, false); }

    private LANG(int nounGender, boolean isIrregularPlural, boolean isConjugated, boolean isLatinScript)
    {
        this.isIrregularPlural = isIrregularPlural;
        this.isConjugated = isConjugated;
        this.isLatinScript = isLatinScript;

        switch(nounGender) {
        case 2:
            this.hasNounGender = true;
            this.hasGenderNeuter = false;
            break;
        case 3:
            this.hasNounGender = true;
            this.hasGenderNeuter = true;
            break;
		default:
            this.hasNounGender = false;
        }
    }

    public String  toString() { return getLongName(); }
    public String  getLongName() { return getLanguageInLanguage(this, this); }
    public String  getName(LANG inLang) { return getLanguageInLanguage(this, inLang); }
    public String  getEnglishName() { return getName(en); }
    public boolean hasNounGender() { return hasNounGender; }
    public boolean hasGenderNeuter() { return hasGenderNeuter; }
    public boolean isIrregularPlural() { return isIrregularPlural; }
    public boolean isConjugated() { return isConjugated; }
    public boolean isLatinScript() { return isLatinScript; }
    public boolean isLeftToRight() { return this == ar || this == fa || this == he; }

    public static String getLanguageInLanguage(LANG toDisplay, LANG in) {
    	String ret = languageNames.get(in.name() + '-' + toDisplay.name());
    	if (ret == null && in != en)
    		ret = languageNames.get("en-" + toDisplay.name());
   		return (ret != null) ? ret : toDisplay.name();
    }

    public boolean isConsoleOk() {
    	switch(this) {
    	case de:
    	case en:
    	case es:
    	case fr:
    	case it:
    	case la:
    	case el:
    	case ru: return true;
    	default: return false;
    	}
    }

    public String getReflexiveVerbDisplay(String word, boolean replaceWordWithPlaceholder) {
    	String disp = replaceWordWithPlaceholder ? WORD_PLACEHOLDER : word;
    	String refPron;
    	switch(this) {
    	case de:
    		refPron = "sich ";
    		break;
    	case es:
    		refPron = "se ";
    		break;
    	case fr:
    		refPron = isFrenchLeadingVowel(word) ? "s'" : "se ";
    		break;
    	case it:
    		refPron = "si ";
    		break;
    	case la:
    		refPron = "se ";
    		break;
    	default:
    		return disp;
    	}
    	return refPron + disp;
    }
    
    private boolean isFrenchLeadingVowel(String word) {
    	char ch = word.charAt(0);
    	if (isVowel(ch))
    		return true;

    	if (ch == 'h') {
        	switch (word.charAt(1)) {
        	case 'a':
        	case 'e':
        	case 'o':
        	case 'u': return true;
        	}
    	}
    	return false;
    }

    public static LANG guess(String lang) {
    	for (LANG l : values())
    		if (l.name().equalsIgnoreCase(lang) || l.getLongName().equalsIgnoreCase(lang) || lang.equalsIgnoreCase(l.getEnglishName()))
    			return l;
    	return null;
    }

    public void toVernacular(String[] sa) throws TransliterateException {
    	for (int i=length(sa)-1; i>=0; --i)
    		sa[i] = toVernacular(sa[i]);
    }

    public String toVernacular(String transliterate) throws TransliterateException {
    	switch(this) {
    	case ru:	return CyrillicScript.toCyrillic(transliterate);
    	case el:	return GreekScript.toGreek(transliterate);
    	default:	return LatinScript.enAccent(transliterate);
    	}
    }

    public void toLatin(String[] sa, boolean withDiacritics) {
    	for (int i=length(sa)-1; i>=0; --i)
    		sa[i] = toLatin(sa[i], withDiacritics);
    }

    public String toLatin(String transliterate, boolean withDiacritics) {
    	switch(this) {
    	case ru:	return CyrillicScript.toLatin(transliterate);
    	case el:	return GreekScript.toLatin(transliterate, withDiacritics);
    	default:	return LatinScript.deAccent(transliterate, withDiacritics);
    	}
    }

    public String toLatin(char transliterate, boolean withDiacritics) {
    	switch(this) {
    	case ru:	return CyrillicScript.toLatin(transliterate);
    	case el:	return GreekScript.toLatin(transliterate, withDiacritics);
    	default:	return String.valueOf(LatinScript.deAccent(transliterate));
    	}
    }

    public boolean isVowel(char ch) {
    	switch(this) {
    	case ru:	return CyrillicScript.isVowel(ch);
    	case el:	return GreekScript.isVowel(ch);
    	default:	return LatinScript.isVowel(ch);
    	}
    }
}
